﻿using System;

using System.Collections.Generic;
using System.Text;
using Fluid.Controls;
using System.Drawing;
using System.Windows.Forms;
using Fluid.Classes;
using PasswordSafe.Classes;

namespace PasswordSafe
{
    public class LoginPanel : FluidPanel
    {

        public LoginPanel(int x, int y, int w, int h)
            : base(x, y, w, h)
        {
        }

        private NumericPad numPad;
        private FluidTextBox passwordTextBox;
        private FluidTextBox newPasswordTextbox;
        private FluidTextBox confirmPasswordTextBox;
        private FluidLabel passwordLabel;
        private FluidLabel newPasswordLabel;
        private FluidLabel confirmPasswordLabel;

        protected override void InitControl()
        {
            base.InitControl();
            EnableDoubleBuffer = true;
            Bounds = new Rectangle(0, 0, 240, 300);
            BackColor = Color.FromArgb(32, 32, 32); // Color.SlateGray;
            //GradientFillOffset = 20;
            //GradientFill = true;
            numPad = new NumericPad(0, 100, Width, 200);

            MakeButtonsGlowing();

            numPad.EnableDoubleBuffer = false;
            numPad.Buttons[15].Enabled = false;
            numPad.Corners = Fluid.Drawing.RoundedCorners.None;
            numPad.Anchor = System.Windows.Forms.AnchorStyles.None;
            numPad.Buttons[11].Text = "Exit";
            numPad.Buttons[11].BackColor = Color.FromArgb(48, 0, 0);
            numPad.SpecialKeyClick += new EventHandler(numPad_SpecialKeyClick);
            numPad.ButtonClick += new EventHandler<NumericPanelEventArgs>(numPad_ButtonClick);
            FluidButton btn = numPad.Buttons[7];
            btn.Format.FormatFlags = 0;
            btn.LineAlignment = StringAlignment.Near;
            btn.Alignment = StringAlignment.Center;
            //numPad.Buttons[11].BackColor = Color.DarkRed;   //Color.FromArgb(48, 0, 0)
            //numPad.Buttons[15].BackColor = Color.DarkGreen;
            numPad.Enter += new EventHandler(numPad_Enter);
            numPad.Anchor = AnchorStyles.None;
            Controls.Add(numPad);

            passwordTextBox = AddTextLabel(PasswordText, 5, ref passwordLabel, true);
            passwordTextBox.TextChanged += new EventHandler(textbox_TextChanged);
            passwordTextBox.Top += 4;
            newPasswordTextbox = AddTextLabel("Enter your new Password", 50, ref newPasswordLabel, false);
            confirmPasswordTextBox = AddTextLabel("Confirm your new Password", 94, ref confirmPasswordLabel, false);

            OnModeChanged();


            numPad.TextChanged += new EventHandler(numPad_TextChanged);
            passwordTextBox.TextChanged += new EventHandler(textbox_TextChanged);
            newPasswordTextbox.TextChanged += new EventHandler(textbox_TextChanged);
            confirmPasswordTextBox.TextChanged += new EventHandler(textbox_TextChanged);
            passwordTextBox.GotFocus += new EventHandler(passwordTextBox_GotFocus);
            newPasswordTextbox.GotFocus += new EventHandler(passwordTextBox_GotFocus);
            confirmPasswordTextBox.GotFocus += new EventHandler(passwordTextBox_GotFocus);
            SelectedTextBox = passwordTextBox;
        }

        private void MakeButtonsGlowing()
        {
            FluidButton[] buttons = numPad.Buttons;
            foreach (FluidButton btn in buttons) btn.PressedBackColor = Color.DarkBlue;
            buttons[11].PressedBackColor = Color.Red;
            buttons[15].PressedBackColor = Color.Green;
        }

        /// <summary>
        /// Gets or sets the password.
        /// </summary>
        public string Password { get { return passwordTextBox.Text; } set { passwordTextBox.Text = value; } }

        /// <summary>
        /// Gets or sets the new password.
        /// </summary>
        internal string NewPassword { get { return newPasswordTextbox.Text; } set { newPasswordTextbox.Text = value; } }

        /// <summary>
        /// Gets or sets the confirmed password.
        /// </summary>
        internal string ConfirmedPassword { get { return confirmPasswordTextBox.Text; } set { confirmPasswordTextBox.Text = value; } }


        private FluidTextBox selectedTextBox;

        public FluidTextBox SelectedTextBox
        {
            get { return selectedTextBox; }
            set
            {
                selectedTextBox = value;
                numPad.Text = selectedTextBox.Text;
                passwordTextBox.BackColor = selectedTextBox == passwordTextBox ? Color.White : Color.Gray;
                newPasswordTextbox.BackColor = selectedTextBox == newPasswordTextbox ? Color.White : Color.Gray;
                confirmPasswordTextBox.BackColor = selectedTextBox == confirmPasswordTextBox ? Color.White : Color.Gray;
            }
        }

        void passwordTextBox_GotFocus(object sender, EventArgs e)
        {
            SelectedTextBox = (FluidTextBox)sender;
        }

        void numPad_ButtonClick(object sender, NumericPanelEventArgs e)
        {
            if (e.ButtonIndex == 7)
            {
                e.Handled = true;
                Mode = Mode == DisplayMode.ChangePassword ? DisplayMode.Login : DisplayMode.ChangePassword;
            }

        }

        void numPad_SpecialKeyClick(object sender, EventArgs e)
        {
            ExitApplication();
        }

        /// <summary>
        /// Exits the application with an animation:
        /// </summary>
        private void ExitApplication()
        {
            this.Parent.BackColor = Color.Black;
            this.Close(ShowTransition.FromBottom);
            PasswordForm.Instance.Close();
        }

        protected string PasswordText
        {
            get
            {
                return mode == DisplayMode.Login ? "Enter your Password" : "Enter your old Password";
            }
        }


        public enum DisplayMode
        {
            Login,
            ChangePassword
        }

        public string Text
        {
            get { return numPad.Text; }
            set { numPad.Text = value; }
        }

        private DisplayMode mode = DisplayMode.Login;

        public DisplayMode Mode
        {
            get { return mode; }
            set
            {
                if (mode != value)
                {
                    mode = value;
                    OnModeChanged();
                }
            }
        }

        public override void OnKeyPress(KeyPressEventArgs e)
        {
            base.OnKeyPress(e);
            switch (e.KeyChar)
            {
                case '\t':
                    e.Handled = SelectNextTextBox();
                    break;

                case '\r':
                    e.Handled = true;
                    PerformEnter();
                    break;
            }
        }

        public override void OnKeyDown(KeyEventArgs e)
        {
            base.OnKeyDown(e);
            if (!e.Handled)
            {
                switch (e.KeyCode)
                {
                    case Keys.Down:
                        e.Handled = PerformKeyDown();
                        break;

                    case Keys.Up:
                        e.Handled = PerformKeyUp();
                        break;
                }
            }
        }

        private bool PerformKeyUp()
        {
            if (mode == DisplayMode.Login) return false;
            if (selectedTextBox == confirmPasswordTextBox) SelectedTextBox = newPasswordTextbox;
            else if (selectedTextBox == newPasswordTextbox) SelectedTextBox = passwordTextBox;
            else return false;
            return true;
        }

        private bool PerformKeyDown()
        {
            if (mode == DisplayMode.Login) return false;
            if (selectedTextBox == passwordTextBox) SelectedTextBox = newPasswordTextbox;
            else if (selectedTextBox == newPasswordTextbox) SelectedTextBox = confirmPasswordTextBox;
            else return false;
            return true;
        }

        private bool SelectNextTextBox()
        {
            if (mode == DisplayMode.ChangePassword)
            {
                bool focused = selectedTextBox.Focused;
                if (selectedTextBox == passwordTextBox) SelectedTextBox = newPasswordTextbox;
                else if (selectedTextBox == newPasswordTextbox) SelectedTextBox = confirmPasswordTextBox;
                else SelectedTextBox = passwordTextBox;
                return true;
                //                selectedTextBox.Focus();
                //                selectedTextBox.SelectAll();
            }
            return false;
        }

        private void OnModeChanged()
        {
            FluidButton btn = numPad.Buttons[7];

            bool visible = mode == DisplayMode.ChangePassword;
            newPasswordLabel.Visible = visible;
            confirmPasswordLabel.Visible = visible;
            newPasswordTextbox.Visible = visible;
            confirmPasswordTextBox.Visible = visible;
            if (mode == DisplayMode.Login)
            {
                btn.TextOffset = new Point(0, 12);
                btn.LineAlignment = StringAlignment.Near;
                passwordTextBox.Focus();
                selectedTextBox = passwordTextBox;
                btn.Text = "Change\nPassword";
                btn.Font = new Font(FontFamily.GenericSansSerif, 7f, FontStyle.Regular);

            }
            else
            {
                btn.TextOffset = new Point(0, 0);
                btn.LineAlignment = StringAlignment.Center;
                btn.Text = "Login";
            }
            numPad.Buttons[15].Text = mode == DisplayMode.Login ? "Enter" : "Change";
            EnsureEnterEnabled();
        }

        FluidTextBox AddTextLabel(string title, int top, ref FluidLabel label, bool visible)
        {
            label = new FluidLabel(title, 10, top + 5, Width - 20, 16);
            label.Anchor = AnchorStyles.Left | AnchorStyles.Top;
            label.Font = new Font(FontFamily.GenericSansSerif, 8f, FontStyle.Regular);
            label.ForeColor = Color.White;
            label.ShadowColor = Color.Black;
            label.Visible = visible;
            Controls.Add(label);

            FluidTextBox textbox = new FluidTextBox("", 10, top + 19, Width - 20, 24);
            textbox.Anchor = AnchorStyles.Left | AnchorStyles.Top;
            textbox.PasswordChar = '*';
            textbox.Visible = visible;
            textbox.CanShowInputPanel = false;
            Controls.Add(textbox);
            return textbox;
        }

        /// <summary>
        /// Filter out the keys that are note allowed:
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void textbox_KeyPress(object sender, KeyPressEventArgs e)
        {
            if ("0123456789\r\x1b\b".IndexOf(e.KeyChar) < 0)
            {
                e.Handled = true;
            }
        }

        private HandledEventArgs changedPasswordEvent = new HandledEventArgs();

        void numPad_Enter(object sender, EventArgs e)
        {
            PerformEnter();
        }

        private void PerformEnter()
        {
            switch (mode)
            {
                case DisplayMode.Login:
                    OnEnter();
                    break;

                case DisplayMode.ChangePassword:
                    OnChangePassword();
                    break;
            }
        }

        protected virtual void OnEnter()
        {
            if (Enter != null)
            {
                changedPasswordEvent.Handled = false;
                if (OnPasswordVerify())
                {
                    Enter(this, EventArgs.Empty);
                }
                else
                {
                    ShowIncorrectPasswordDialog();
                }
            }
        }

        private void ShowIncorrectPasswordDialog()
        {
            Password = "";
            SelectedTextBox = passwordTextBox;
            MessageDialog.Show("Incorrect password. \nPlease retype your Password.", "", null);
        }

        void dlg_Result(object sender, DialogEventArgs e)
        {
            if (e.Result == DialogResult.Cancel)
            {
                ExitApplication();
            }
        }

        protected virtual void OnChangePassword()
        {
            if (ChangePassword != null)
            {
                if (!OnPasswordVerify())
                {
                    ShowIncorrectPasswordDialog();
                }
                else
                {
                    changedPasswordEvent.Handled = false;
                    ChangePassword(this, changedPasswordEvent);
                    if (!changedPasswordEvent.Handled)
                    {
                        MessageDialog.Show(
                            "Failure while encrypting the file: \nDecrypting with the password failed.\nPlease try another password.", null, "OK", Color.DarkRed);
                    }
                    else
                    {
                        Password = NewPassword;
                        NewPassword = ConfirmedPassword = "";
                        Mode = DisplayMode.Login;
                    }
                }
            }
        }

        public event EventHandler<HandledEventArgs> ChangePassword;
        public event EventHandler Enter;

        void textbox_TextChanged(object sender, EventArgs e)
        {
            EnsureEnterEnabled();
        }

        public void EnsureEnterEnabled()
        {
            numPad.Text = selectedTextBox.Text;

            if (mode == DisplayMode.Login)
            {
                numPad.Buttons[15].Enabled = true;
            }
            else
            {
                numPad.Buttons[15].Enabled = NewPassword == ConfirmedPassword;
            }
        }

        private PasswordEventArgs passwordVerfyEventArgs = new PasswordEventArgs();

        private bool OnPasswordVerify()
        {
            if (ConfirmPassword != null)
            {
                Host.Cursor = Cursors.WaitCursor;
                passwordVerfyEventArgs.Handled = false;
                passwordVerfyEventArgs.Password = Password;
                ConfirmPassword(this, passwordVerfyEventArgs);
                Host.Cursor = Cursors.Default;
                return passwordVerfyEventArgs.Handled;

            }
            else return false;
        }

        /// <summary>
        /// Occurs when the current password must be verified with the actual password.
        /// </summary>
        public event EventHandler<PasswordEventArgs> ConfirmPassword;

        void numPad_TextChanged(object sender, EventArgs e)
        {
            string text = numPad.Text;
            if (this.selectedTextBox.Text != text)
            {
                this.selectedTextBox.Text = text;
                selectedTextBox.Select(Password.Length, 0);
            }
        }


        protected override void OnSizeChanged(System.Drawing.Size oldSize, System.Drawing.Size newSize)
        {
            base.OnSizeChanged(oldSize, newSize);
            int w0 = Width;
            int h0 = Height;

            if (h0 > w0)
            {
                LayoutVertical(w0);
            }
            else
            {
                LayoutHorizontal(h0);
            }

        }

        private void LayoutHorizontal(int h0)
        {
            if (Controls.Count == 0) return;
            foreach (FluidControl c in Controls)
            {
                if (c.Anchor != AnchorStyles.None)
                {
                    c.Width = ScaleX(170);
                }
            }
            int l = passwordTextBox.Right + ScaleX(6);

            numPad.Bounds = new Rectangle(l, -2, Width - l + 1, h0 + 4);
        }

        private void LayoutVertical(int w0)
        {
            if (Controls.Count == 0) return;
            foreach (FluidControl c in Controls)
            {
                if (c.Anchor != AnchorStyles.None)
                {
                    c.Width = w0 - ScaleX(20);
                }
            }
            int top = this.confirmPasswordTextBox.Bottom + ScaleY(6);
            int hmax = numPad.ButtonHeight * 4;
            int l = -1;
            int h = Height - top - l;
            if (hmax < h)
            {
                h = hmax;
                top = Height - h - l;
            }
            else
            {
                top = Height - h - l;
            }
            numPad.Bounds = new Rectangle(l, top, Width - l - l, h + 1);
        }

    }
}
